const { DbError } = require('../error')
const O = {
  Regex: {
    FloatUnsign: /^\d+(\.\d+)?$/, //非负浮点数
    FloatSign: /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/, //负浮点数
  },
  /**
   *  SyntaxError（语法错误）
   *  ReferenceError（引用错误）
   *  RangeError（范围错误）
   *  TypeError（类型错误）
   *  URLError（URL错误）
   *  EvalError（eval错误）
   */
  Err: Object.freeze({
    Syntax: 'sy:',
    Reference: 're:',
    Range: 'ra:',
    Type: 'ty:',
    Eval: 'ev:',
  }),
   /**
   * throw Error : condition is false && falseErr is not false
   * throw Error : condition is true  && trueErr is not false
   * return boolean
   */
  getFlag(condition, falseErr = false, trueErr = false) {
    if (falseErr !== false && !condition){
      this.throws(falseErr)
    }else if(trueErr !== false && condition){
      this.throws(trueErr)
    }
    return !!condition
  },
  getErrMsg(string='',df=''){
    if(string === false){
      return false
    }else if(typeof string!= 'string'){
      return df
    }else if(string.startsWith(':')){
      return 'ty:' + string.slice(1) +' ' + df
    }else if(string===''){
      return df
    }else{
      return string + df
    }
  },
  dbErr(e){
    throw new DbError(e.errno, e.code)
  },
  wrapRouter(fn) {
    // if (this.isPromise(fn)) { // 无效
    if (this.isAsyncFunction(fn)){
      // (res,rsp,next)=>{ res.json('dosomething') }
      return (...args) => fn(...args).catch(args[2])
    }else{
      return fn
    }
  },
  isAsyncFunction(fn){
    let fnStr = fn.toString() || ''
    return Object.prototype.toString.call(fn) === '[object AsyncFunction]' || fnStr.includes("return _regenerator.default.async(function")
  },
  awaits(promise) {
    return promise
      .then(data => [null, data])
      .catch(err => [err, null])
  },
  throws(err='err') {
    if(err.startsWith(this.Err.Syntax)) {
      throw SyntaxError(err.slice(this.Err.Syntax.length))
    } else if (err.startsWith(this.Err.Reference)) {
      throw ReferenceError(err.slice(this.Err.Reference.length))
    } else if (err.startsWith(this.Err.Range)) {
      throw RangeError(err.slice(this.Err.Range.length))
    } else if (err.startsWith(this.Err.Type)) {
      throw TypeError(err.slice(this.Err.Type.length))
    } else if (err.startsWith(this.Err.Eval)) {
      throw EvalError(err.slice(this.Err.Eval.length))
    }else{
      throw Error(err)
    }
  },
  isFalse(obj, errMsg='should not be false') {
    this.getFlag(!obj, false, this.getErrMsg(errMsg))
    // this.getFlag(obj == false, false, `ty: ${errMsg}  should not false`)
  },
  isTrue(obj, errMsg = 'should not be true') {
    // 需要用 Boolean(obj)==true  or  obj != false or  !!obj
    this.getFlag(!!obj, false, this.getErrMsg(errMsg))
    // this.getFlag(Boolean(obj) == true, false, `ty: ${errMsg}  should not false`)
  },
  // obj是否定义了 field 属性/方法
  def(obj, field , falseErr=false,trueErr = false){
    // return typeof obj[field] !== 'undefined'
    return this.getFlag(obj[field] =='undefined'
      , this.getErrMsg(falseErr,`re:${field} is not defined`)
      , this.getErrMsg(trueErr,`re:${field} should not defined`))
  },
  isArray(arr, falseErr = false, trueErr = false) {
    return this.getFlag(arr.constructor === Array
      , this.getErrMsg(falseErr, 'is not Array')
      , this.getErrMsg(trueErr,'should not Array'))
  },
  isArrayEmp(arr,falseErr = false,trueErr=false) {
    this.isArray(arr,'')
    return this.getFlag(arr.length < 1
      , this.getErrMsg(falseErr ,'is not empty Array')
        , this.getErrMsg(trueErr ,'should not empty Array'))
  },
  isFunction(func, falseErr = false, trueErr = false) {
    return this.getFlag(func.constructor === Function
      , this.getErrMsg(falseErr,'is not function')
        , this.getErrMsg(trueErr,'should not function'))
  },
  isNumber(number, falseErr = false, trueErr = false) {
    return this.getFlag(typeof number == 'number'
      , this.getErrMsg(falseErr,'is not number')
        , this.getErrMsg(trueErr,'should not number'))
  },
  isNumberString(val,falseErr=false,trueErr=false) {
    flag = this.Regex.FloatSign.test(val) || this.Regex.FloatUnsign.test(val)
    return this.getFlag(flag
      , this.getErrMsg(falseErr,'is not number or number format string')
      , this.getErrMsg(trueErr, 'should not number or number format string'))
  },
  isNumberBet(number,start,end, falseErr = false, trueErr = false) {
    return this.getFlag(typeof number == 'number' && number>=start && number<=end
      , this.getErrMsg(falseErr ,'only assist ')
        , this.getErrMsg(trueErr ,'should not number'))
  },
  isObject(obj, falseErr = false, trueErr = false) {
    return this.getFlag(obj.constructor === Object
      , this.getErrMsg(falseErr, 'is not object')
        , this.getErrMsg(trueErr, 'should not object'))
  },
  isObjectEmp(obj, falseErr = false, trueErr = false) {
    this.isObject(obj,'')
    return this.getFlag(Object.keys(obj).length==0
      , this.getErrMsg(falseErr ,'is not empty object' )
        , this.getErrMsg(trueErr ,'should not empty object'))
  },
  isPromise(obj,falseErr=false,trueErr=false) {
    const flag = (!!obj &&
      (typeof obj === "object" || typeof obj === "function") &&
      typeof obj.then === "function");
    return this.getFlag(flag
      , this.getErrMsg(falseErr , 'is not promise')
        , this.getErrMsg(trueErr , 'should not promise'))
  },
  isString(str, falseErr = false, trueErr = false) {
    return this.getFlag(typeof str === 'string'
      , this.getErrMsg( falseErr,'is not string')
        , this.getErrMsg(trueErr,'should not string'))

  },
  isStringEmp(str, falseErr = false, trueErr = false) {
    return this.getFlag(typeof str === 'string' && !str
      , this.getErrMsg(falseErr , 'is not string')
        , this.getErrMsg(trueErr , 'should not string'))

  },
  isStringOrNum(obj, falseErr = false, trueErr = false){
    return this.getFlag(['string', 'number'].includes(typeof obj)
      , this.getErrMsg(falseErr , 'is not string|number')
        , this.getErrMsg(trueErr , 'should not string|number'))
  },
}
// 不要暴露和引用具体方法 防止this意外失效
module.exports = O